package com.linghang.back.service.impl;

import com.linghang.back.dto.*;
import com.linghang.back.entity.User;
import com.linghang.back.exception.BusinessException;
import com.linghang.back.exception.ErrorCode;
import com.linghang.back.repository.UserRepository;
import com.linghang.back.service.UserService;
import com.linghang.back.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {
    
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private RetryTemplate redisRetryTemplate;
    
    // Redis中验证码的Key前缀
    private static final String VERIFY_CODE_PREFIX = "user:verify:code:";
    // 验证码有效期（分钟）
    private static final int VERIFY_CODE_EXPIRE_MINUTES = 5;

    @Override
    @Retryable(value = {DataAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 500, multiplier = 2))
    public String sendVerifyCode(VerifyCodeRequest request) {
        String mobile = request.getMobile();
        logger.info("开始为手机号 {} 生成验证码", mobile);
        
        // 生成4位随机验证码
        String verifyCode = generateRandomCode(4);
        
        // 使用重试模板来保存验证码到Redis
        try {
            String redisKey = VERIFY_CODE_PREFIX + mobile;
            redisRetryTemplate.execute(retryContext -> {
                logger.debug("尝试将验证码保存到Redis，尝试次数: {}", retryContext.getRetryCount() + 1);
                redisTemplate.opsForValue().set(redisKey, verifyCode, VERIFY_CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
                return verifyCode;
            });
            
            // TODO: 调用短信API发送验证码
            // 这里直接打印验证码，实际中会发送给用户
            logger.info("向手机号[{}]发送验证码：{}", mobile, verifyCode);
            
            return verifyCode;
        } catch (Exception e) {
            logger.error("保存验证码到Redis失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "验证码生成失败，请稍后再试");
        }
    }

    @Override
    @Transactional
    public UserResponse register(RegisterRequest request) {
        // 验证手机号是否已注册
        if (userRepository.existsByMobile(request.getMobile())) {
            throw ErrorCode.USER_MOBILE_EXISTS.exception();
        }
        
        // 验证用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw ErrorCode.USER_USERNAME_EXISTS.exception();
        }
        
        // 验证验证码
        String redisKey = VERIFY_CODE_PREFIX + request.getMobile();
        String savedCode = redisTemplate.opsForValue().get(redisKey);
        if (savedCode == null || !savedCode.equals(request.getVerifyCode())) {
            throw ErrorCode.VERIFY_CODE_ERROR.exception();
        }
        
        // 创建用户
        User user = new User();
        user.setMobile(request.getMobile());
        user.setUsername(request.getUsername());
        user.setPassword(request.getPassword());  // 实际应用中应该加密密码
        user.setRegisterTime(LocalDateTime.now());
        user.setLastLoginTime(LocalDateTime.now());
        
        // 处理邀请关系
        if (request.getInviteCode() != null && !request.getInviteCode().isEmpty()) {
            Optional<User> inviter = userRepository.findByInviteCode(request.getInviteCode());
            if (inviter.isPresent()) {
                user.setInviterId(inviter.get().getId());
            }
        }
        
        // 保存用户
        user = userRepository.save(user);
        
        // 生成邀请码
        String inviteCode = generateInviteCode(user.getId());
        user.setInviteCode(inviteCode);
        user = userRepository.save(user);
        
        // 删除Redis中的验证码
        redisTemplate.delete(redisKey);
        
        // 生成token
        String token = jwtUtil.generateToken(user.getId().toString());
        
        // 转换为响应对象
        UserResponse response = convertToUserResponse(user);
        response.setToken(token);
        
        return response;
    }

    @Override
    @Transactional
    public UserResponse login(LoginRequest request) {
        // 验证验证码
        String redisKey = VERIFY_CODE_PREFIX + request.getMobile();
        String savedCode = redisTemplate.opsForValue().get(redisKey);
        if (savedCode == null || !savedCode.equals(request.getVerifyCode())) {
            throw ErrorCode.VERIFY_CODE_ERROR.exception();
        }
        
        // 删除Redis中的验证码
        redisTemplate.delete(redisKey);
        
        // 检查用户是否存在
        Optional<User> userOpt = userRepository.findByMobile(request.getMobile());
        User user;
        
        if (userOpt.isEmpty()) {
            // 用户不存在，自动注册
            user = new User();
            user.setMobile(request.getMobile());
            // 使用手机号作为默认用户名，用户后续可以修改
            user.setUsername("user_" + request.getMobile().substring(7));
            user.setRegisterTime(LocalDateTime.now());
            
            // 处理邀请关系
            if (request.getInviteCode() != null && !request.getInviteCode().isEmpty()) {
                Optional<User> inviter = userRepository.findByInviteCode(request.getInviteCode());
                if (inviter.isPresent()) {
                    user.setInviterId(inviter.get().getId());
                }
            }
            
            // 保存用户
            user = userRepository.save(user);
            
            // 生成邀请码
            String inviteCode = generateInviteCode(user.getId());
            user.setInviteCode(inviteCode);
        } else {
            // 用户存在，更新登录时间
            user = userOpt.get();
        }
        
        // 更新最后登录时间
        user.setLastLoginTime(LocalDateTime.now());
        user = userRepository.save(user);
        
        // 生成token
        String token = jwtUtil.generateToken(user.getId().toString());
        
        // 转换为响应对象
        UserResponse response = convertToUserResponse(user);
        response.setToken(token);
        
        return response;
    }

    @Override
    public UserResponse getUserInfo(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> ErrorCode.USER_NOT_FOUND.exception());
        
        return convertToUserResponse(user);
    }

    @Override
    public String generateInviteCode(Long userId) {
        // 生成基于用户ID的唯一邀请码
        String baseCode = UUID.randomUUID().toString().substring(0, 8).toUpperCase();
        String inviteCode = baseCode + userId % 1000; // 添加用户ID的一部分，增加辨识度
        
        // 更新用户信息
        User user = userRepository.findById(userId)
                .orElseThrow(() -> ErrorCode.USER_NOT_FOUND.exception());
        user.setInviteCode(inviteCode);
        userRepository.save(user);
        
        return inviteCode;
    }

    @Override
    @Transactional
    public boolean bindInviter(Long userId, String inviteCode) {
        // 找到当前用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> ErrorCode.USER_NOT_FOUND.exception());
        
        // 用户已经有邀请人，不能再绑定
        if (user.getInviterId() != null) {
            throw ErrorCode.INVITER_ALREADY_BOUND.exception();
        }
        
        // 查找邀请码对应的用户
        Optional<User> inviterOpt = userRepository.findByInviteCode(inviteCode);
        if (inviterOpt.isEmpty()) {
            throw ErrorCode.INVITE_CODE_INVALID.exception();
        }
        
        // 不能自己邀请自己
        User inviter = inviterOpt.get();
        if (inviter.getId().equals(userId)) {
            throw ErrorCode.CANNOT_INVITE_SELF.exception();
        }
        
        // 设置邀请关系
        user.setInviterId(inviter.getId());
        userRepository.save(user);
        
        return true;
    }
    
    /**
     * 生成指定长度的随机数字验证码
     */
    private String generateRandomCode(int length) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }
    
    /**
     * 将User实体转换为UserResponse DTO
     */
    private UserResponse convertToUserResponse(User user) {
        UserResponse response = new UserResponse();
        BeanUtils.copyProperties(user, response);
        // 不返回敏感信息
        return response;
    }
} 